﻿
using MetroNextTools.NBase;
using MetroNextTools.NData;
using MetroNextTools.NEventArgs;
using MetroNextTools.NPanel;
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using Windows.ApplicationModel;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Media;

namespace MetroNextTools.NControls
{
    #region AccessibilityItem

    public sealed class AccessibilityItem
    {
        private object _item;

        public object Item
        {
            get { return _item; }
        }
        public AccessibilityItem(object item)
        {
            this._item = item;
        }
    }

    #endregion


    /// <summary>
    /// 集合控件的基类
    /// 默认具有模版功能
    /// 
    /// TODO 添加对CollectionViewSource的支持
    /// </summary>
    public class NItemsControl : NTemplateControl, INGeneratorHost
    {
        #region Fields

        private NCollection _items = null;
        private NItemContainerGenerator _itemContainerGenerator = null;
        private PropertyInfo _displayMemberPropInfo = null;

        private ScrollViewer _scrollContainer = null;
        private IItemsPresenter _itemsPresenter = null;
        private NCollectionPanel _itemsContainer = null;

        #endregion

        #region Constructor

        public NItemsControl()
        {
            this.DefaultStyleKey = typeof(NItemsControl);
            _items = new NCollection();
            _itemContainerGenerator = new NItemContainerGenerator(this);
            _items.CollectionChanged += OnNCollectionChanged;
            _itemContainerGenerator.ItemsChanged += OnInternalItemsChangedHanlder;
        }

        #endregion

        #region ApplyTemplte
        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _scrollContainer = (ScrollViewer)base.GetTemplateChild("PART_ScrollContainer");
            _itemsPresenter = (IItemsPresenter)base.GetTemplateChild("PART_ItemsPresenter");
            _itemsContainer = _itemsPresenter.ItemsPanel;
        }

        protected override void OnLoaded(object sender, RoutedEventArgs e)
        {
            base.OnLoaded(sender, e);
            if (DesignMode.DesignModeEnabled)
            {
                InitUIData();
            }
        }

        private void InitUIData()
        {
            IEnumerator enumerator = this.Items._itemsSource.GetEnumerator();
            int i = 0;
            while (enumerator.MoveNext())
            {
                INRaitoItem item = enumerator.Current as INRaitoItem;
                Rect rect = _itemsContainer.CaculatePosition(item);
                NGeneratorPosition position = new NGeneratorPosition(i, rect);
                AddContainerForPosition(position);
                i++;
            }
        }

        #endregion

        #region DependencyProperties

        #region IsGrouping Property

        public bool IsGrouping
        {
            get { return (bool)GetValue(IsGroupingProperty); }
            set { SetValue(IsGroupingProperty, value); }
        }

        public static readonly DependencyProperty IsGroupingProperty =
            DependencyProperty.Register("IsGrouping", typeof(bool), typeof(NItemsControl), new PropertyMetadata(null));

        #endregion

        #region ItemsSource Property

        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(NItemsControl), new PropertyMetadata(null, new PropertyChangedCallback(ItemsSourceChanged)));

        private static void ItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            NItemsControl itemsControl = d as NItemsControl;
            itemsControl.OnItemsSourceChanged((IEnumerable)e.OldValue, (IEnumerable)e.NewValue);
            //itemsControl.ClearContainers(false);//清楚面板上的内容
            itemsControl._items.UpdateItemsSourceList((IEnumerable)e.NewValue);
        }

        #endregion

        #region ItemContainerGenerator Property
        public NItemContainerGenerator ItemContainerGenerator
        {
            get { return _itemContainerGenerator; }
        }
        #endregion

        #region ItemOfGeneratedContainer Attached Property

        internal static void SetItemOfGeneratedContainer(DependencyObject element, AccessibilityItem value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            if (value != null)
            {
                element.SetValue(ItemOfGeneratedContainerProperty, value);
                return;
            }
            element.ClearValue(ItemOfGeneratedContainerProperty);
        }

        internal static AccessibilityItem GetItemOfGeneratedContainer(DependencyObject element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            return (AccessibilityItem)element.GetValue(ItemOfGeneratedContainerProperty);
        }

        internal static readonly DependencyProperty ItemOfGeneratedContainerProperty =
            DependencyProperty.RegisterAttached("ItemOfGeneratedContainer", typeof(AccessibilityItem), typeof(NItemsControl), new PropertyMetadata(null));


        #endregion

        #endregion

        #region Implements IGeneratorHost

        #region Items Property

        public NCollection Items
        {
            get { return this._items; }
        }

        #endregion

        #region ItemsHost Property

        public NCollectionPanel ItemsHost
        {
            get
            {
                if (_itemsContainer == null)
                {
                    this.ApplyTemplate();
                }
                return _itemsContainer;
            }
        }
        #endregion

        bool INGeneratorHost.IsItemItsOwnContainer(object item)
        {
            return IsItemItsOwnContainerOverride(item);
        }

        public DependencyObject GetContainerForItem(object item, DependencyObject recycledContainer)
        {
            UIElement element;
            if (IsItemItsOwnContainerOverride(item))
            {
                element = (item as UIElement);
                if (element == null)
                {
                    throw new ArgumentNullException("NItemsControl Items must be an UIElement");
                }
                if (this.Items.ItemsSourceActive() && this.ItemTemplate != null)
                {
                    throw new NotSupportedException("NItemsControl items must not be an UIElement when ItemplateIsSet");
                }
                NItemsControl.SetItemOfGeneratedContainer(element, null);
            }
            else
            {
                if (recycledContainer != null)
                {
                    element = (recycledContainer as UIElement);
                }
                else
                {
                    element = (this.GetContainerForItemOverride() as UIElement);
                }
                if (element == null)
                {
                    throw new NotSupportedException("NItemsControl GetContainerForItemOverride must return a UIElement");
                }
                ContentControl contentControl = element as ContentControl;
                if (contentControl != null)
                {
                    //TODO SetContentIsNotLogic???
                }
                NItemsControl.SetItemOfGeneratedContainer(element, new AccessibilityItem(item));
            }
            return element;
        }

        void INGeneratorHost.PrepareItemContainer(DependencyObject container, object item)
        {
            this.PrepareContainerForItemOverride(container, item);
        }

        void INGeneratorHost.ClearContainerForItem(DependencyObject container, object item)
        {
            this.ClearContainerForItemOverride(container, item);
        }

        bool INGeneratorHost.IsHostForItemContainer(DependencyObject container)
        {
            NItemsControl itemsControl = NItemsControl.ItemsControlFromItemContainer(container);
            if (itemsControl != null)
            {
                return itemsControl == this;
            }
            DependencyObject dependencyObject = null;
            FrameworkElement frameworkElement = container as FrameworkElement;
            if (frameworkElement != null)
            {
                dependencyObject = frameworkElement.Parent;
            }
            return dependencyObject == null && (this.IsItemItsOwnContainerOverride(container) && this.Items.Count > 0) && this.Items.Contains(container);
        }

        #endregion

        #region Static Method

        /// <summary>
        /// 根据一个ItemContianer 来获取他的ItemsControl
        /// </summary>
        /// <param name="container"></param>
        /// <returns></returns>
        private static NItemsControl ItemsControlFromItemContainer(DependencyObject container)
        {
            UIElement element = container as UIElement;
            if (element == null)
            {
                return null;
            }
            DependencyObject dependencyObject = null;
            FrameworkElement frameworkElement = container as FrameworkElement;
            if (frameworkElement != null)
            {
                dependencyObject = frameworkElement.Parent;
            }
            NItemsControl itemsControl = dependencyObject as NItemsControl;
            if (itemsControl == null)
            {
                dependencyObject = VisualTreeHelper.GetParent(element);
                return NItemsControl.GetItemsOwner(dependencyObject);
            }
            if (itemsControl.IsItemItsOwnContainerOverride(element))
            {
                return itemsControl;
            }
            return null;
        }

        /// <summary>
        /// 获取他的宿主控件
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        public static NItemsControl GetItemsOwner(DependencyObject element)
        {
            NItemsControl itemsControl = null;
            Panel panel = element as Panel;
            if (panel != null && panel.IsItemsHost)
            {
                ItemsPresenter itemsPresenter = VisualTreeHelper.GetParent(panel) as ItemsPresenter;
                if (itemsPresenter != null)
                {
                    itemsControl = VisualTreeHelper.GetParent(itemsPresenter) as NItemsControl;
                    if (itemsControl == null)
                    {
                        element = itemsPresenter;
                        while (element != null && !(element is ItemsControl))
                        {
                            element = VisualTreeHelper.GetParent(element);
                        }
                        itemsControl = (element as NItemsControl);
                    }
                }
                return itemsControl;
            }
            return itemsControl;
        }
        #endregion

        #region EventHandler

        void OnNCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.OnItemsChanged(e);
        }

        void OnInternalItemsChangedHanlder(object sender, NItemsChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    this.AddContainerForPosition(e.Position);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    this.RemoveContainerForPosition(e.Position);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    this.RemoveContainerForPosition(e.Position);
                    this.AddContainerForPosition(e.Position);
                    break;
                case NotifyCollectionChangedAction.Reset:
                    this.ClearContainers(false);
                    break;
                case NotifyCollectionChangedAction.Move:
                    break;
                default:
                    break;
            }
            //这个地方不是ItemsPanel 而是 ItemsPanel 的父节点Grid
            this._itemsPresenter.ItemsPanelHost.Width = this.ItemsHost.GetMaxLength() + this.Padding.Left;
        }




        #endregion

        #region Method

        #region Virtual Method
        protected virtual void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
        {

        }

        /// <summary>
        /// 用来继承的集合变化时的方法
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {

        }

        protected virtual bool IsItemItsOwnContainerOverride(object item)
        {
            return item is UIElement;
        }

        protected virtual DependencyObject GetContainerForItemOverride()
        {
            return new ContentPresenter();
        }

        protected virtual void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            if (object.ReferenceEquals(item, element))
            {
                return;
            }
            //ContentPresenter , ContentControl
            ContentPresenter contentPresenter = (ContentPresenter)element;
            ContentControl contentControl = null;
            if (contentPresenter == null)
            {
                contentControl = (ContentControl)element;
                if (contentControl == null)
                {
                    return;
                }
            }
            //ItemTemplate DisplayMemberPath
            if (this.ItemTemplate != null && this._displayMemberPathCache != null)
            {
                throw new InvalidOperationException("ItemTemplate , DisplayMemberPath can only be set one.");
            }
            if (!(item is UIElement))
            {
                DataTemplate contentTemplate = GetItemTemplate(item, element);
                object content = item;
                if (this._displayMemberPathCache != null)
                {
                    content = ReflectPropertyValueAndStoreInfoIfNeeded(ref this._displayMemberPropInfo, item, _displayMemberPathCache);
                }
                if (contentPresenter != null)
                {
                    contentPresenter.Content = content;
                    contentPresenter.ContentTemplate = contentTemplate;
                }
                else
                {
                    contentControl.Content = content;
                    contentControl.ContentTemplate = contentTemplate;
                }
            }
        }

        protected virtual void ClearContainerForItemOverride(DependencyObject container, object item)
        {

        }

        internal virtual object ReflectPropertyValueAndStoreInfoIfNeeded(ref PropertyInfo cachedPropInfo, object source, string propertyPath)
        {
            Type type = source.GetType();
            if (cachedPropInfo != null && cachedPropInfo.Name == propertyPath && cachedPropInfo.DeclaringType == type)
            {
                return cachedPropInfo.GetValue(source);
            }
            if (!string.IsNullOrEmpty(propertyPath))
            {
                cachedPropInfo = type.GetTypeInfo().GetDeclaredProperty(propertyPath);
                if (cachedPropInfo != null)
                {
                    return cachedPropInfo.GetValue(source);
                }
            }
            return null;
        }
        #endregion

        #region Container Operation

        private void AddContainerForPosition(NGeneratorPosition generatorPosition)
        {
            _itemContainerGenerator.StartAt(generatorPosition, GeneratorDirection.Forward);
            bool needPrepareContainer = false;
            //在这一步声称Conainer（是循环利用的） Container是有ItemContainerGenerator协调生成的，而Container的位置有ItemHost生成，生成位置后关系又ItemContainerGenerator完成。
            DependencyObject container = _itemContainerGenerator.GenertateNext(out needPrepareContainer);
            int index = this._itemContainerGenerator.IndexFromGeneratorPosition(generatorPosition);
            //根据添加到容器中，如果需要设置DataTemplate则设置一下DataTemplate
            this.AddVisualChild(index, container, needPrepareContainer);
        }

        private void RemoveContainerForPosition(NGeneratorPosition generatorPosition)
        {

        }

        private void ClearContainers(bool bHostIsReplaced)
        {
            if (this.ItemsHost == null)
            {
                return;
            }
            this.ItemsHost.Children.Clear();
        }


        private void AddVisualChild(int index, DependencyObject container, bool needPrepareContainer)
        {
            UIElementCollection children = this.ItemsHost.Children;
            if (index < children.Count)
            {
                children.Insert(index, container as UIElement);
            }
            else
            {
                children.Add(container as UIElement);
            }
            if (needPrepareContainer)
            {
                this._itemContainerGenerator.PrepareItemContainer(container);
            }
        }


        #endregion

        #endregion
    }
}
